<!DOCTYPE html>


<html lang="zh-CN">
  

    <head>
      <meta charset="utf-8" />
       
      <meta name="keywords" content="Hexo,Hexo主题,ayer,代码,博客,旅行" />
       
      <meta name="description" content="Hexo主题Ayer中文说明" />
      
      <meta
        name="viewport"
        content="width=device-width, initial-scale=1, maximum-scale=1"
      />
      <title>网站搬家记录 |  岛</title>
  <meta name="generator" content="hexo-theme-ayer">
      
      <link rel="shortcut icon" href="/favicon.ico" />
       
<link rel="stylesheet" href="/dist/main.css">

      
<link rel="stylesheet" href="/css/fonts/remixicon.css">

      
<link rel="stylesheet" href="/css/custom.css">
 
      <script src="https://cdn.staticfile.org/pace/1.2.4/pace.min.js"></script>
       
 

      <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/npm/@sweetalert2/theme-bulma@5.0.1/bulma.min.css"
      />
      <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.19/dist/sweetalert2.min.js"></script>

      <!-- mermaid -->
      
      <style>
        .swal2-styled.swal2-confirm {
          font-size: 1.6rem;
        }
      </style>
    <link rel="alternate" href="/atom.xml" title="岛" type="application/atom+xml">
</head>
  </html>
</html>


<body>
  <div id="app">
    
      
    <main class="content on">
      <section class="outer">
  <article
  id="post-网站搬家记录"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  网站搬家记录
</h1>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/2020/wangzhanbanjia/" class="article-date">
  <time datetime="2020-07-16T12:45:28.000Z" itemprop="datePublished">2020-07-16</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/%E6%8A%80%E6%9C%AF/">技术</a>
  </div>
  
<div class="word_count">
    <span class="post-time">
        <span class="post-meta-item-icon">
            <i class="ri-quill-pen-line"></i>
            <span class="post-meta-item-text"> 字数统计:</span>
            <span class="post-count">2.1k</span>
        </span>
    </span>

    <span class="post-time">
        &nbsp; | &nbsp;
        <span class="post-meta-item-icon">
            <i class="ri-book-open-line"></i>
            <span class="post-meta-item-text"> 阅读时长≈</span>
            <span class="post-count">7 分钟</span>
        </span>
    </span>
</div>
 
    </div>
      
    <div class="tocbot"></div>




  
    <div class="article-entry" itemprop="articleBody">
       
  <blockquote>
<p>记录第一次用宝塔面板搬迁wordpress网站，附性能优化+防黑。</p>
</blockquote>
<p>最近把网站从虚拟主机搬迁到了vps，由于是第一次搬网站，又不太懂运维和服务器知识，期间踩了不少坑，在此记录一下，也希望对遇到同样问题的朋友有所帮助。首先，如果你的流量比较大，为了不影响用户最好选准时间段，我的网站早晨是一个流量低谷，所以我是定好闹钟6点起床开搞的，记得在完成搬迁之前，原有服务器上的网站先别急着删掉，这样可以随时通过域名解析就能恢复。</p>
<span id="more"></span>

<h3 id="宝塔面板的安装和配置"><a href="#宝塔面板的安装和配置" class="headerlink" title="宝塔面板的安装和配置"></a>宝塔面板的安装和配置</h3><p>宝塔面板的安装在这里我就不说了，网上一抓一大把，实在不行看官网教程一步步走下去就行，这边我为了自己做备忘，简单记录下面板里需要设置的东西。</p>
<h4 id="非必须的配置"><a href="#非必须的配置" class="headerlink" title="非必须的配置"></a>非必须的配置</h4><ul>
<li>如果是国内云服务器厂商，需要在面板导入出站规则和入站规则。</li>
<li>如果是有多块磁盘，需要运行一下自动挂载</li>
</ul>
<h4 id="LNMP的一键安装"><a href="#LNMP的一键安装" class="headerlink" title="LNMP的一键安装"></a>LNMP的一键安装</h4><p>这边所安装的php和nginx版本最好和原有服务器的版本一样。</p>
<h4 id="优化服务器效率"><a href="#优化服务器效率" class="headerlink" title="优化服务器效率"></a>优化服务器效率</h4><p>用 linux工具箱配置swap</p>
<p>安装php拓展：opcache, memcached, magemagick, fileinfo, exif</p>
<ul>
<li>开启memcached缓存步骤：下载解压memcached对应的<a target="_blank" rel="noopener" href="https://github.com/tollmanz/wordpress-pecl-memcached-object-cache">wordpress插件</a> ，上传到 wp-content 目录下面，然后再wp-config里面添加两行<code>define(&#39;ENABLE_CACHE&#39;, true);define(&#39;WP_CACHE&#39;, true);</code> </li>
</ul>
<h4 id="安全配置"><a href="#安全配置" class="headerlink" title="安全配置"></a>安全配置</h4><ol>
<li>修改账号密码</li>
<li>修改面板端口</li>
<li>修改服务器的SSH端口</li>
<li>禁止ping</li>
<li>开启监控</li>
</ol>
<h3 id="转移网站和数据库"><a href="#转移网站和数据库" class="headerlink" title="转移网站和数据库"></a>转移网站和数据库</h3><p>把网站根目录和数据库打包备份到本地，这里注意一点，原先的网站最好压缩成tar.gz的后缀，防止在转移之后中文文件名出现乱码，至于数据库什么格式都行，然后通过宝塔面板上传导入，网站上传放到wwwroot下，数据库正常导入。然后在网站那个页面添加一个新站点，域名添加两个，一个带www的一个不带www的，目录指向wwwroot下面的那个网站目录，如果是wordpress或者其他cms程序的话，还需要设置伪静态规则，直接选中点确定就行。至此，网站和数据库就转移完成，接下来连接数据库。</p>
<h3 id="连接数据库"><a href="#连接数据库" class="headerlink" title="连接数据库"></a>连接数据库</h3><p>把wordpress目录下的wp-config文件中的数据库信息修改成新的，其他的cms程序都有对应的配置文件，记得找到修改一下，这样网站才能正确连接到数据库。</p>
<h3 id="ssl证书迁移"><a href="#ssl证书迁移" class="headerlink" title="ssl证书迁移"></a>ssl证书迁移</h3><p>如果你的网站是https的，那就需要转移ssl证书，这边宝塔面板还是很方便的。可以申请宝塔的免费证书(有效期1年)，也可以自行导入第三方证书，我用的是阿里云的免费ssl证书，也是一年有效期。第三方证书都只要把证书的内容复制粘贴到框里就行了，</p>
<h3 id="开放端口"><a href="#开放端口" class="headerlink" title="开放端口"></a>开放端口</h3><p>这里我折腾了很久，也不知道是因为我之前ssl没部署还是端口没开放的原因，反正我遇到了cloudflare 522错误，这个错误的意思其实是通过域名已经能连到cloudflare，但是cloudflare连不到你的服务器。<strong>这里千万要记得：</strong>把vps服务商和宝塔面板的端口，如什么80啊433啊，该开放的都开放，并且把cloudflare的IP段加入白名单，不然可能会因为阻止了cloudflare的IP段而造成无法正确解析，这里排查要点主要是以下两点，我就原话复制过来了：</p>
<ul>
<li>请确保你没有在.htaccess，iptables的，或您的防火墙阻止CloudFlare的IP地址。</li>
<li>确保您的托管服务提供商是不是速率限制或阻止来自CloudFlare的IP地址IP请求，并要求他们在白名单地址中提到的IP地址<a target="_blank" rel="noopener" href="http://www.cloudflare.com/ips">http://www.cloudflare.com/ips</a></li>
</ul>
<h3 id="域名解析"><a href="#域名解析" class="headerlink" title="域名解析"></a>域名解析</h3><p>这一步还是比较简单的，如果你之前用的是vps，换一下ip就行，如果你之前用的是虚拟主机，那就把CNAME解析换成A解析，然后把地址改成ip。如果你用cloudflare做了CDN加速，并且把原先域名服务商的DNS服务器换成了cloudflare的，那么你原先的域名服务商的解析就会被cloudflare托管，这时候需要在cloudflare的DNS页面修改解析。</p>
<h3 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h3><h4 id="图片无法显示"><a href="#图片无法显示" class="headerlink" title="图片无法显示"></a>图片无法显示</h4><p>由于原先主机是linux的原因，如果迁移不当则会造成中文文件名乱码，导致新网站就显示不出图片了。这边有3种解决方法。</p>
<ul>
<li>第一种方法就是在迁移的时候把网站压缩成tar.gz的格式，这样linux是可以保留中文名的，但有些主机的cpanel是只支持zip压缩的，这样就需要用到第二种解决方法了。</li>
<li>第二种方法，先用FTP软件把uploads目录，也就是存储文件的目录下到本地，然后用脚本把文件名都批量替换成拼音的，最后再把uploads目录上传到新的服务器上，我用的是<a target="_blank" rel="noopener" href="https://github.com/guiqiqi/WPChineseAttachFix">这个脚本</a>，装个python用命令行py一下就行了，执行完会生成一段sql命令，进入数据库执行一下就好了。</li>
<li>第三种方法，如果你网站的图片不多的话，那么还是手动改吧，这样更加靠谱并且能防止出错。</li>
</ul>
<h4 id="cloudflare国内速度慢"><a href="#cloudflare国内速度慢" class="headerlink" title="cloudflare国内速度慢"></a>cloudflare国内速度慢</h4><p>Cloudflare is fast except in China. 如果你的用户主要在国内，并且网站不是什么灰色产业，那还是建议域名做备案，然后通过国内的云加速做CDN，因为CF在国内的CDN实在是有点慢，如果真不想做备案，那就去掉cloudflare的CDN，只需要把DNS面板的proxy status点成DNS only就行了，这样cloudflare就只做域名解析，如果有其他子域名解析到其他站点，那同样需要把子域名的proxy去掉，不然会出现ssl证书匹配不上的问题。最好是都加上proxy或者干脆都不加，我的根域名去掉之后发现backblaze的流量无法代理过去了，所以后来就又都加上了。</p>
<p>我实测了一下，国内访问的话，去掉cloudflare的CDN加速服务确实比加了CDN要快，当然，前提是机房在亚洲，如果在欧美，那还是老实套上cloudflare吧，其实套上cloudflare也是能接受的，没有网上说的那么不堪。如果你的用户主要在海外，那放心白嫖cloudflare就完事了，你会发现香的一批。</p>
<h4 id="webshell查杀"><a href="#webshell查杀" class="headerlink" title="webshell查杀"></a>webshell查杀</h4><p>一旦网站seo上去了，如果防护没做到位，被盯上挂后门是很常见的事情，这时候会严重影响用户浏览，还会使网站体积越来越大。我最近就遇到了一起被人恶意挂webshell的事情，前几天我通过bing搜到自己的网站，点进去发现强制重定向到雅虎日本了，但是在其他搜索引擎是好的，于是我就找原因，点开index文件发现一大串乱码，当时我就意识到被黑了，我原本以为只是简单的改了index文件，后来经过查杀才知道好几个目录都被下了乱码的php文件，隔几天就来改我一次，删了还是有。所以我就上网找查杀工具，打算把源头揪出来，webshell的查杀工具有很多，我用的是深信服的WebShellKiller。</p>
<p>后来经过一系列的仔细对比搜索，我发现源头似乎在主题里，网上查了一下，确实很多黑链后门都是在第三方主题中，所以主题千万别上哪个论坛随便下，网上很多cms主题都被改了而且留了后门。主题目录下有个functions.php文件，可以重点关注一下这个文件。</p>
 
      <!-- reward -->
      
      <div id="reword-out">
        <div id="reward-btn">
          打赏
        </div>
      </div>
      
    </div>
    

    <!-- copyright -->
    
    <div class="declare">
      <ul class="post-copyright">
        <li>
          <i class="ri-copyright-line"></i>
          <strong>版权声明： </strong>
          
          本博客所有文章除特别声明外，著作权归作者所有。转载请注明出处！
          
        </li>
      </ul>
    </div>
    
    <footer class="article-footer">
       
<div class="share-btn">
      <span class="share-sns share-outer">
        <i class="ri-share-forward-line"></i>
        分享
      </span>
      <div class="share-wrap">
        <i class="arrow"></i>
        <div class="share-icons">
          
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="ri-weibo-fill"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="ri-wechat-fill"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="ri-qq-fill"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="ri-douban-line"></i>
          </a>
          <!-- <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a> -->
          
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="ri-facebook-circle-fill"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="ri-twitter-fill"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="ri-google-fill"></i>
          </a>
        </div>
      </div>
</div>

<div class="wx-share-modal">
    <a class="modal-close" href="javascript:;"><i class="ri-close-circle-line"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="//api.qrserver.com/v1/create-qr-code/?size=150x150&data=https://shen-yu.gitee.io/2020/wangzhanbanjia/" alt="微信分享二维码">
    </div>
</div>

<div id="share-mask"></div>  
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E6%8A%80%E6%9C%AF/" rel="tag">技术</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E7%94%9F%E6%B4%BB/" rel="tag">生活</a></li></ul>

    </footer>
  </div>

   
  <nav class="article-nav">
    
      <a href="/2020/chartjs/" class="article-nav-link">
        <strong class="article-nav-caption">上一篇</strong>
        <div class="article-nav-title">
          
            在 Hexo 中插入 Chart 动态图表
          
        </div>
      </a>
    
    
      <a href="/2020/hexo-seo/" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">hexo-seo优化技巧</div>
      </a>
    
  </nav>

  
   
    
    <script src="https://cdn.staticfile.org/twikoo/1.4.18/twikoo.all.min.js"></script>
    <div id="twikoo" class="twikoo"></div>
    <script>
        twikoo.init({
            envId: "ayer-blog-8gua74e95b0290a2"
        })
    </script>
 
</article>

</section>
      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2015-2022
        <i class="ri-heart-fill heart_icon"></i> Eric Shen
      </li>
    </ul>
    <ul>
      <li>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>访问人数:<span id="busuanzi_value_site_uv"></span></span>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>浏览次数:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src='https://s9.cnzz.com/z_stat.php?id=1278069914&amp;web_id=1278069914'></script>
        
      </li>
    </ul>
  </div>
</footer>    
    </main>
    <div class="float_btns">
      <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

    </div>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="/images/ayer-side.svg" alt="岛"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/categories">分类</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags/%E6%97%85%E8%A1%8C/">旅行</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" target="_blank" rel="noopener" href="http://shenyu-vip.lofter.com">摄影</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/friends">友链</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/2019/about">关于我</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/player">播放器</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="搜索">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="/images/alipay.jpg">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="/images/wechat.jpg">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
    
<script src="/js/jquery-3.6.0.min.js"></script>
 
<script src="/js/lazyload.min.js"></script>

<!-- Tocbot -->
 
<script src="/js/tocbot.min.js"></script>

<script>
  tocbot.init({
    tocSelector: ".tocbot",
    contentSelector: ".article-entry",
    headingSelector: "h1, h2, h3, h4, h5, h6",
    hasInnerContainers: true,
    scrollSmooth: true,
    scrollContainer: "main",
    positionFixedSelector: ".tocbot",
    positionFixedClass: "is-position-fixed",
    fixedSidebarOffset: "auto",
  });
</script>

<script src="https://cdn.staticfile.org/jquery-modal/0.9.2/jquery.modal.min.js"></script>
<link
  rel="stylesheet"
  href="https://cdn.staticfile.org/jquery-modal/0.9.2/jquery.modal.min.css"
/>
<script src="https://cdn.staticfile.org/justifiedGallery/3.8.1/js/jquery.justifiedGallery.min.js"></script>

<script src="/dist/main.js"></script>

<!-- ImageViewer -->
 <!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.staticfile.org/photoswipe/4.1.3/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.staticfile.org/photoswipe/4.1.3/default-skin/default-skin.min.css">
<script src="https://cdn.staticfile.org/photoswipe/4.1.3/photoswipe.min.js"></script>
<script src="https://cdn.staticfile.org/photoswipe/4.1.3/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script> 
<!-- MathJax -->

<!-- Katex -->

<!-- busuanzi  -->
 
<script src="/js/busuanzi-2.3.pure.min.js"></script>
 
<!-- ClickLove -->

<!-- ClickBoom1 -->

<!-- ClickBoom2 -->

<!-- CodeCopy -->
 
<link rel="stylesheet" href="/css/clipboard.css">
 <script src="https://cdn.staticfile.org/clipboard.js/2.0.10/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>
 
<!-- CanvasBackground -->

<script>
  if (window.mermaid) {
    mermaid.initialize({ theme: "forest" });
  }
</script>


    
    

  </div>
</body>

</html>